﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration;
using System.Runtime.Serialization;
using com.codeplex.eatoutadvocate.Web.Mvc.Models;
using com.codeplex.eatoutadvocate.Web.Mvc.Engine;

namespace com.codeplex.eatoutadvocate.Web.Mvc.Services
{
    public class EatOutAdvocateService
    {
        private EatOutAdvocateDataContext data;
        public EatOutAdvocateService()
        {
            data = new EatOutAdvocateDataContext(ConfigurationManager.ConnectionStrings["EatOutAdvocateData"].ConnectionString);
        }
        
        /// <summary>
        /// DB Connection String
        /// </summary>
        
        private static string ConnectionString
        {
            get
            {
                return ConfigurationManager.ConnectionStrings["EatOutAdvocateData"].ConnectionString;
            }
        }

        public List<string> GetRestaurants(string term)
        {

            //Establish Data connection
            IQueryable<string> restaurants;

            restaurants = (from r in data.Restaurants
                                where r.Name.ToLower().Contains(term.ToLower())
                                select r.Name).Take(50); // If list size is > 50, just get the first 50 ones

            return (restaurants == null) ? Enumerable.Empty<string>().AsQueryable().ToList() : restaurants.ToList();
        }

        /// <summary>
        /// Checks if specified user exists in UserData table
        /// </summary>
        /// <param name="user">UserData name to check</param>
        /// <returns>
        /// True: UserData exists
        /// False: UserData doesn't exist
        /// </returns>
        public bool UserExists(string user)
        {
            //Establish Data connection
            int count;
            count = (from u in data.Users
                    where u.Email == user
                    select u).Count();
            if (count > 0)
                return true;
            else
                return false;
        }


                
        public void Store(long fbtoken, EatOutModel eatout)
        {
            User user = (from u in data.Users
                            where u.UserFacebookToken == fbtoken
                            select u).First();

            int rid = -1;
            bool parsed = Int32.TryParse(eatout.Restaurant, out rid);
            Restaurant restaurant = (from r in data.Restaurants
                                        where r.ID == rid
                                        select r).First();
            if (rid == -1 || null == restaurant)
            {
                throw new InputValidationException("Restaurant"); // TODO: Catch
            }
            EatOut eatOutDB = new EatOut();
            eatOutDB.User = user;
            eatOutDB.Mood = eatout.Mood;
            eatOutDB.MoodLevel = eatout.MoodLevel;
            eatOutDB.Restaurant = restaurant;
            eatOutDB.Temperature = eatout.Temperature;
            eatOutDB.Weather = eatout.Weather;
            eatOutDB.TimeHour = eatout.Time;
            eatOutDB.TimeStamp = DateTime.Now;

            data.EatOuts.InsertOnSubmit(eatOutDB);
            data.SubmitChanges();
        }

        public List<string> Recommend(long fbtoken, EatOutModel eo)
        {
            List<EatOut> eatouts;
            
            User user = (from u in data.Users
                            where u.UserFacebookToken == fbtoken
                            select u).First();
            /* If user doesn't exist, throw exception */
            if (null == user)
            {
                throw new NoUserException(); //TODO: Catch this exception in controller and send user to login screen
            }
            eatouts = (from eos in data.EatOuts
                                    where eos.User == user
                                    select eos).ToList<EatOut>();
            if (null == eatouts)
            {
                throw new InsufficientDataException(); // TODO: UserData will then be taken to Record page??
            }
            // Compute score
            Score.InitUser(eo.Time, eo.Mood, eo.MoodLevel, eo.Weather, eo.Temperature);
            foreach (EatOut eatout in eatouts)
            {
                eatout.Score = Score.Compute(eatout);
            }

            return Recommendation.Recommend(eatouts);
        }

        public bool CreateUser(long fbtoken, string email, string fname, string lname)
        {
            try
            {
                User user = new User();
                user.UserFacebookToken = fbtoken;
                user.Email = email;
                user.Fname = fname;
                user.Lname = lname;
                //user.UserFacebookToken = userId;

                data.Users.InsertOnSubmit(user);
                data.SubmitChanges();

                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }


        public bool UserExists(long fbtoken)
        {
            if (fbtoken == -1)
                return false;
            else
            {
                try
                {

                    int count = (from u in data.Users
                                    where u.UserFacebookToken == fbtoken
                                    select u).Count();
                    if (count <= 0)
                        return false;
                    else 
                        return true;

                }
                catch (Exception)
                {
                    return false;
                }
            }
        }
    }

    [Serializable()]
    /* NoUserException: Will be thrown if the user sent does not exist in DB */
    public class NoUserException : Exception, ISerializable
    {
        public NoUserException() : base() { }
        public NoUserException(string message) : base(message) { }
        public NoUserException(string message, System.Exception inner) : base(message, inner) { }
        public NoUserException(SerializationInfo info, StreamingContext context) : base(info, context) { }
    }

    [Serializable()]
    /* InputValueException: Will be thrown if input values sent does not validate */
    public class InputValidationException : Exception, ISerializable
    {
        public InputValidationException() : base() { }
        public InputValidationException(string message) : base(message) { }
        public InputValidationException(string message, System.Exception inner) : base(message, inner) { }
        public InputValidationException(SerializationInfo info, StreamingContext context) : base(info, context) { }
    }

    [Serializable()]
    /* InputValueException: Will be thrown if input values sent does not validate */
    public class InsufficientDataException : Exception, ISerializable
    {
        public InsufficientDataException() : base() { }
        public InsufficientDataException(string message) : base(message) { }
        public InsufficientDataException(string message, System.Exception inner) : base(message, inner) { }
        public InsufficientDataException(SerializationInfo info, StreamingContext context) : base(info, context) { }
    }


}